执行期上下文
执行器上下文的概念贯穿于 JavaScript 引擎解释代码的全过程,这个概念是一个运行期的概念,执行器上下文一般实现为一个栈。按照 ECMAScript 的规范,一共有三种类型 的代码,全局代码(游离于任何函数体之外),函数代码,以及 eval 代码(eval 接受字符串,并对这个字符串求值,通常来讲,函数式编程都会提供这个函数或者类似的机制)。这三种代码均在自身的执行期上下文中求值。全局上下文仅有一个,函数上下文和 eval 上下文则可能有多个。
引擎在调用一个函数时,进入该函数上下文,并执行函数体,与其他程序设计语言类似,函数体内可以有递归,也可以调用其他函数(进入另外一个上下文,此时调用者被阻塞,直至返回)。调用 eval 会有类似的情况。
引擎在初始化之后,将 golbal 的上下文对象压入栈:
图 执行期上下文栈(初始状态)
(function(name){
print("hello, "+name);
})("jack");
执行上边代码的时候,进入函数执行期上下文,将匿名函数执行期上下文压入栈中:
图 进入函数执行期上下文
执行完成之后,弹出该上下文对象。既然执行期上下文栈中存放的是执行期上下文对象, 那么我们来详细看看这个对象的结构。上文提到,ECMAScript 代码有三类,对应的执行期 上下文对象也有三类,每个上下文对象都有一些必须的属性用以为执行于其上的代码服务,以及记录/跟踪代码执行状态等。
一个典型的上下文对象的结构如下:
图 上下文对象结构
当然,根据不同的实现,这个对象可以包含任意其他的属性(上图中的<properties>
部分)。每个上下文对象所需要包含的有变量对象,作用域链以及 this.这三个属性在不同类型的上下文对象中意义可能不同。
变量对象只是一个抽象概念,在全局上下文中,变量对象是全局变量自身。而在函数上下文中,变量对象表现为活动对象,活动对象将在下一小节展开,对于 eval 上下文,eval 可能使用全局的变量对象,也可能使用函数的变量对象,这取决于其调用的位置。因此可以说,变量对象有两类,全局的变量对象(全局变量 global 本身或者活动对象,eval 使用这两者之一)。
结合执行器上下文栈和原型对象,我们可以得到下列的示意图:
图 执行器上下文栈及变量对象,原型链示意图
{$ activeFileHint $}